package com.heima.wemedia.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.feign.article.ArticleFeignClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmAutoScanService;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.text.StrBuilder;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class WmAutoScanServiceImpl implements WmAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private GreenTextScan textScan;
    @Autowired
    private GreenImageScan imageScan;
    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private ArticleFeignClient articleFeignClient;
    @Autowired
    private WmChannelMapper wmChannelMapper;
    @Autowired
    private WmUserMapper wmUserMapper;
    @Autowired
    private Tess4jClient tess4jClient;
    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;


    /**
     * 根据文章id去审核该文章
     *
     * @param newsId
     */
    @Override
    public ResponseResult autoScan(Integer newsId) {
        //1.查询自媒体文章
        WmNews wmNews = wmNewsMapper.selectById(newsId);
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.AP_USER_DATA_NOT_EXIST, "当前文章不存在");
        }
        //如果是草稿就不审核
        if (wmNews.getStatus() == 0) {
            return ResponseResult.okResult(null);
        }
        //2.抽取统计当前wmnews中的文本和图片
        Map map = chouquImageAndText(wmNews);

        //自管理的敏感词过滤
        boolean sensitiveScanFlag = handleSensitiveScan((String) map.get("content"), wmNews);
        if (!sensitiveScanFlag) {
            return ResponseResult.errorResult(AppHttpCodeEnum.SCAN_IMAGE_FAILER);
        }


        //3.文章文本审核
        Boolean textflag = handleTextScan(wmNews, (String) map.get("content"));
        if (!textflag) {
            return ResponseResult.errorResult(AppHttpCodeEnum.SCAN_TEXT_FAILER);
        }
        //4.文章图片审核
        Boolean imageflag = handleImageScan(wmNews, (List) map.get("images"));
        if (!imageflag) {
            return ResponseResult.errorResult(AppHttpCodeEnum.SCAN_IMAGE_FAILER);
        }
        //5.审核通过调用feign接口，保存article三剑客
        ResponseResult result = saveArticle(wmNews);
        //6.修改wm_news表中的状态9
//        wmNews.setArticleId(Long.valueOf(result.getData().toString()));
        wmNews.setArticleId((Long) result.getData());
        updateNews(wmNews, (short) 9, "审核成功");


        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }


    /**
     * 自管理的敏感词审核
     *
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleSensitiveScan(String content, WmNews wmNews) {
        boolean flag = true;
        //获取所有的敏感词
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
        List<String> sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());

        //初始化敏感词库
        SensitiveWordUtil.initMap(sensitiveList);

        //查看文章中是否包含敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if (map.size() > 0) {
            updateNews(wmNews, (short) 2, "当前文章中存在违规内容" + map);
            flag = false;
        }

        return flag;
    }


    //第五个抽取的方法，保存三剑客
    private ResponseResult saveArticle(WmNews wmNews) {
        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNews, dto);

        //文章的布局
        dto.setLayout(wmNews.getType());
        //频道
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if (wmChannel != null) {
            dto.setChannelName(wmChannel.getName());
        }

        //作者
        dto.setAuthorId(wmNews.getUserId().longValue());
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if (wmUser != null) {
            dto.setAuthorName(wmUser.getName());
        }

        /*try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/

        //设置文章id
        if (wmNews.getArticleId() != null) {
            dto.setId(wmNews.getArticleId());
        }
        dto.setCreatedTime(new Date());
        //调用fegin接口
        ResponseResult result = articleFeignClient.saveArticle(dto);

        return result;
    }

    /**
     * 第四个抽取方法，审核图片
     *
     * @param wmNews
     * @param images
     * @return
     */
    private Boolean handleImageScan(WmNews wmNews, List<String> images) {
        //申明一个标识 true 表示审核通过 false表示失败或者人工
        boolean flag = true;
        //定义一个list数组存储下载图片字节
        List<byte[]> byteList = new ArrayList<>();
        if (images != null && images.size() > 0) {
            for (String imagePath : images) {
                //先下载图片
                byte[] bytes = fileStorageService.downLoadFile(imagePath);
                //图片识别文字审核---begin-----
                //从byte[]转换为butteredImage
                ByteArrayInputStream is = new ByteArrayInputStream(bytes);
                BufferedImage imageFile = null;
                try {
                    imageFile = ImageIO.read(is);
                    //识别图片的文字
                    String result = tess4jClient.doOCR(imageFile);
                    //审核是否包含自管理的敏感词
                    boolean isSensitive = handleSensitiveScan(result, wmNews);
                    if (!isSensitive) {
                        updateNews(wmNews, (short) 2, "图片内容有敏感词，审核失败");
                        return isSensitive;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                byteList.add(bytes);
            }
        }
        //调用阿里云接口
        try {
            Map map = imageScan.imageScan(byteList);
            //如果审核失败
            if (map.get("suggestion").equals("block")) {
                //修改wm_news表中的状态为status=2
                updateNews(wmNews, (short) 2, "图片内容有违规，审核失败");
                flag = false;
            } else if (map.get("suggestion").equals("review")) {
                updateNews(wmNews, (short) 3, "图片内容疑似有问题,请申请人工审核");
                flag = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        }
        return flag;
    }


    /**
     * 抽取第二个方法 把图片和内容进行分开
     *
     * @param wmNews
     */
    private Map chouquImageAndText(WmNews wmNews) {

        //定义一个list集合用来存储拆开的图片
        List<String> imageList = new ArrayList();
        //定义字符串，用于拼接文章内容
        StrBuilder sb = new StrBuilder();

        //获取文章内容
        String content = wmNews.getContent();
        List<Map> list = JSON.parseArray(content, Map.class);
        for (Map map : list) {
            //文本
            if (map.get("type").equals("text")) {
                Object value = map.get("value");
                sb.append(value);
            }
            //图片
            else if (map.get("type").equals("image")) {
                Object value = map.get("value");
                imageList.add((String) value);
            }
            //去重
            imageList = imageList.stream().distinct().collect(Collectors.toList());
        }
        //其他文字
        sb.append(wmNews.getTitle());
        //封面图片
        if (wmNews.getImages() != null) {
            String[] split = wmNews.getImages().split(",");
            imageList.addAll(Arrays.asList(split));
        }

        //返回数据
        Map dataMap = new HashMap();
        dataMap.put("content", sb.toString());
        dataMap.put("images", imageList);
        return dataMap;
    }

    /**
     * 第一个抽取方法，文本审核操作
     *
     * @param wmNews
     */
    private Boolean handleTextScan(WmNews wmNews, String content) {
        //申明一个标识 true 表示审核通过 false表示失败或者人工
        boolean flag = true;
        //直接调用阿里云接口
        try {
            Map map = textScan.greeTextScan(content);
            //如果审核失败
            if (map.get("suggestion").equals("block")) {
                //修改wm_news表中的状态为status=2
                updateNews(wmNews, (short) 2, "文本内容有违规，审核失败");
                flag = false;
            } else if (map.get("suggestion").equals("review")) {
                updateNews(wmNews, (short) 3, "文本内容疑似有问题,请申请人工审核");
                flag = false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        }
        return flag;
    }

    //第三个方法，修改wm_news表
    public void updateNews(WmNews wmNews, Short status, String msg) {
        wmNews.setStatus(status);
        wmNews.setReason(msg);
        wmNewsMapper.updateById(wmNews);
    }

}
